package com.group4.datafactorybackend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.group4.datafactorybackend.common.R;
import com.group4.datafactorybackend.common.enums.MyEnumClass;
import com.group4.datafactorybackend.common.enums.ResultCodeEnum;
import com.group4.datafactorybackend.entity.DO.ApiDO;
import com.group4.datafactorybackend.entity.DO.DaDirectoryDO;
import com.group4.datafactorybackend.entity.DO.DirectoryDO;
import com.group4.datafactorybackend.entity.DTO.CreateOrUpdateDirectoryDTO;
import com.group4.datafactorybackend.entity.VO.DirectoryVO;
import com.group4.datafactorybackend.mapper.ApiMapper;
import com.group4.datafactorybackend.mapper.DaDirectoryMapper;
import com.group4.datafactorybackend.mapper.DirectoryMapper;
import com.group4.datafactorybackend.service.DirectoryService;
import com.group4.datafactorybackend.util.CodeUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author 卑微小峰
 * @date 2022/8/1
 * @description 目录管理业务逻辑实现层
 */
@Service
public class DirectoryServiceImpl extends ServiceImpl<DirectoryMapper, DirectoryDO> implements DirectoryService {

    private final DirectoryMapper directoryMapper;

    private final DaDirectoryMapper daDirectoryMapper;

    private final ApiMapper apiMapper;

    @Autowired
    public DirectoryServiceImpl(DirectoryMapper directoryMapper, DaDirectoryMapper daDirectoryMapper, ApiMapper apiMapper) {
        this.directoryMapper = directoryMapper;
        this.daDirectoryMapper = daDirectoryMapper;
        this.apiMapper = apiMapper;
    }

    /**
     * @author 卑微小峰
     * @param createOrUpdateDirectoryDTO 新增、修改目录接收参数实体类
     * @return R
     * @description 新增目录
     */
    @Override
    public R<?> addDirectory(CreateOrUpdateDirectoryDTO createOrUpdateDirectoryDTO) {
        // 判断传入目录名称不能为空
        if ("".equals(createOrUpdateDirectoryDTO.getDirectoryName().trim())) {
            return R.Failed(ResultCodeEnum.REQUEST_PARAM_NULL.getMessage());
        }

        // 生成目录编号
        String directoryCode = CodeUtil.getCode();
        createOrUpdateDirectoryDTO.setDirectoryCode(directoryCode);

        // 判断如果是数据资产管理新增目录，已有资产表的资产目录下不可以再新建下级目录
        LambdaQueryWrapper<DaDirectoryDO> getDataAssertCountWrapper = new LambdaQueryWrapper<>();
        getDataAssertCountWrapper.eq(DaDirectoryDO::getDirectoryCode,createOrUpdateDirectoryDTO.getParentCode());
        int count = daDirectoryMapper.selectCount(getDataAssertCountWrapper);
        if (MyEnumClass.MenuEnum.MENU_DATA_ASSERT_MANAGEMENT.getCode().equals(createOrUpdateDirectoryDTO.getMenuCode()) && count > 0) {
            return R.Failed(ResultCodeEnum.EXIST_DATA_ASSERT);
        }

        // 判断目录名称是否重复
        R<?> result = this.directoryNameIsRepeat(createOrUpdateDirectoryDTO);
        if (result.getCode() == ResultCodeEnum.SAME_LEVEL_DIRECTORY_NAME_REPEAT.getCode()) {
            return R.Failed(ResultCodeEnum.SAME_LEVEL_DIRECTORY_NAME_REPEAT);
        } else if (result.getCode() == ResultCodeEnum.SAME_PATH_DIRECTORY_NAME_REPEAT.getCode()) {
            return R.Failed(ResultCodeEnum.SAME_PATH_DIRECTORY_NAME_REPEAT);
        } else {
            DirectoryDO directoryDO = new DirectoryDO();
            BeanUtils.copyProperties(createOrUpdateDirectoryDTO, directoryDO);
            int flag = directoryMapper.insert(directoryDO);
            if (flag > 0) {
                return R.Success(ResultCodeEnum.OPERATION_SUCCESS);
            }
            return R.Failed(ResultCodeEnum.OPERATION_FAILED);
        }
    }

    /**
     * @author 卑微小峰
     * @param directoryCode 删除的目录编号
     * @return R
     * @description 删除目录
     */
    @Override
    public R<?> deleteDirectory(String directoryCode) {
        // 查询当前目录下是否含有子目录
        LambdaQueryWrapper<DirectoryDO> getChildDirectoryCountWrapper = new LambdaQueryWrapper<>();
        getChildDirectoryCountWrapper.eq(DirectoryDO::getParentCode,directoryCode);
        int childDirectoryCount = directoryMapper.selectCount(getChildDirectoryCountWrapper);
        if (childDirectoryCount > 0) {
            return R.Failed(ResultCodeEnum.EXIST_CHILD_DIRECTORY);
        }
        // 查询当前目录下是否含有接口
        LambdaQueryWrapper<ApiDO> getApiCountWrapper = new LambdaQueryWrapper<>();
        getApiCountWrapper.eq(ApiDO::getApiDirectoryCode,directoryCode);
        int apiCount = apiMapper.selectCount(getApiCountWrapper);
        if (apiCount > 0) {
            return R.Failed(ResultCodeEnum.EXIST_API);
        }

        LambdaQueryWrapper<DirectoryDO> deleteDirectoryWrapper = new LambdaQueryWrapper<>();
        deleteDirectoryWrapper.eq(DirectoryDO::getDirectoryCode,directoryCode);
        int result = directoryMapper.delete(deleteDirectoryWrapper);
        if (result > 0) {
            return R.Success(ResultCodeEnum.OPERATION_SUCCESS);
        }
        return R.Failed(ResultCodeEnum.OPERATION_FAILED);
    }

    /**
     * @author 卑微小峰
     * @param createOrUpdateDirectoryDTO 编辑目录接收参数DTO
     * @return R
     * @description 编辑目录
     */
    @Override
    public R<?> updateDirectory(CreateOrUpdateDirectoryDTO createOrUpdateDirectoryDTO) {

        // 判断目录名称是否重复
        R<?> result = this.directoryNameIsRepeat(createOrUpdateDirectoryDTO);
        if (result.getCode() == ResultCodeEnum.SAME_LEVEL_DIRECTORY_NAME_REPEAT.getCode()) {
            return R.Failed(ResultCodeEnum.SAME_LEVEL_DIRECTORY_NAME_REPEAT);
        } else if (result.getCode() == ResultCodeEnum.SAME_PATH_DIRECTORY_NAME_REPEAT.getCode()) {
            return R.Failed(ResultCodeEnum.SAME_PATH_DIRECTORY_NAME_REPEAT);
        } else {
            LambdaUpdateWrapper<DirectoryDO> updateDirectoryWrapper = new LambdaUpdateWrapper<>();
            updateDirectoryWrapper.eq(DirectoryDO::getDirectoryCode, createOrUpdateDirectoryDTO.getDirectoryCode())
                    .set(DirectoryDO::getDirectoryName, createOrUpdateDirectoryDTO.getDirectoryName());
            int flag = directoryMapper.update(null, updateDirectoryWrapper);
            if (flag > 0) {
                return R.Success(ResultCodeEnum.OPERATION_SUCCESS);
            }
            return R.Failed(ResultCodeEnum.OPERATION_FAILED);
        }
    }

    /**
     * @author 卑微小峰
     * @param parentCode 菜单编号
     * @return R
     * @description 获取目录列表
     */
    @Override
    public List<DirectoryVO> getDirectoryList(String parentCode) {
        // 查询当前父级编号下的所有子目录
        List<DirectoryVO> childDirectoryVOList = new ArrayList<>();
        LambdaQueryWrapper<DirectoryDO> getChildDirectoryListWrapper = new LambdaQueryWrapper<>();
        getChildDirectoryListWrapper.eq(DirectoryDO::getParentCode, parentCode);
        List<DirectoryDO> childDirectoryDOList = directoryMapper.selectList(getChildDirectoryListWrapper);
        for (DirectoryDO directoryDO : childDirectoryDOList) {
            DirectoryVO directoryVO = new DirectoryVO();
            BeanUtils.copyProperties(directoryDO,directoryVO);
            childDirectoryVOList.add(directoryVO);
        }

        // 如果集合长度大于0，表示存在下级目录，遍历集合查询下级目录,否则直接返回数据
        if (childDirectoryVOList.size() > 0) {
            for (DirectoryVO childDirectory : childDirectoryVOList) {
                //再通过其id作为pid查询他的下级目录
                childDirectory.setChildren(getDirectoryList(childDirectory.getDirectoryCode()));
            }
        }
        return childDirectoryVOList;
    }

    /**
     * @author 卑微小峰
     * @param cuDirectoryDTO 新增、修改目录接收参数实体类
     * @return boolean
     * @description 判断目录名称是否重复
     */
    public R<?> directoryNameIsRepeat(CreateOrUpdateDirectoryDTO cuDirectoryDTO) {

        // 判断同一上级分类的多个下级分类是否重名
        // 查询新增目录的父级下的所有子目录名称（与新增目录同级目录名称）
        LambdaQueryWrapper<DirectoryDO> getChildDirectoryNameListByParentCodeWrapper = new LambdaQueryWrapper<>();
        getChildDirectoryNameListByParentCodeWrapper.eq(DirectoryDO::getParentCode, cuDirectoryDTO.getParentCode())
                .ne(DirectoryDO::getDirectoryCode, cuDirectoryDTO.getDirectoryCode());
        List<DirectoryDO> directoryDOList = directoryMapper.selectList(getChildDirectoryNameListByParentCodeWrapper);

        // 判断新增目录的父级下是否存在子目录,存在才判断是否与同级重名
        if (directoryDOList.size() > 0) {
            for (DirectoryDO directoryDO : directoryDOList) {
                if (cuDirectoryDTO.getDirectoryName().trim().equals(directoryDO.getDirectoryName())) {
                    // 目录名称与同级目录重名
                    return R.Failed(ResultCodeEnum.SAME_LEVEL_DIRECTORY_NAME_REPEAT);
                }
            }
        }

        // 判断此目录是否为顶级目录，如果是顶级则同路径上没有父目录,不是则调用方法，检查是否与同路径上的父级目录重名
        if (!cuDirectoryDTO.getParentCode().equals(cuDirectoryDTO.getMenuCode().toString())) {
            List<String> parentDirectoryNameList = new ArrayList<>();
            // 获取同路径上父级目录名称列表
            parentDirectoryNameList = this.pathParentDirectoryNameIsRepeat(cuDirectoryDTO.getParentCode(),parentDirectoryNameList);
            for (String name : parentDirectoryNameList) {
                if (cuDirectoryDTO.getDirectoryName().trim().equals(name)) {
                    return R.Failed(ResultCodeEnum.SAME_PATH_DIRECTORY_NAME_REPEAT);
                }
            }
        }

        // 判断此目录是否存在下级目录，存在则调用方法，检查是否与同路径上的子级目录重名
        LambdaQueryWrapper<DirectoryDO> getChildDirectoryCountWrapper = new LambdaQueryWrapper<>();
        getChildDirectoryCountWrapper.eq(DirectoryDO::getParentCode,cuDirectoryDTO.getDirectoryCode());
        int childDirectoryCount = directoryMapper.selectCount(getChildDirectoryCountWrapper);
        if (childDirectoryCount > 0) {
            List<String> childDirectoryNameList = new ArrayList<>();
            this.pathChildDirectoryNameIsRepeat(cuDirectoryDTO.getDirectoryCode(),childDirectoryNameList);
            for (String name : childDirectoryNameList) {
                if (cuDirectoryDTO.getDirectoryName().trim().equals(name)) {
                    return R.Failed(ResultCodeEnum.SAME_PATH_DIRECTORY_NAME_REPEAT);
                }
            }

        }
        return R.Success();
    }

    /**
     * @author 卑微小峰
     * @param parentCode 父级目录编号
     * @param parentDirectoryNameList 父级目录名称集合
     * @return List
     * @description 递归查询同路径上的父级目录
     */
    @Override
    public List<String> pathParentDirectoryNameIsRepeat(String parentCode,List<String> parentDirectoryNameList) {
        LambdaQueryWrapper<DirectoryDO> directoryNameIsExistAtParentDirectoryWrapper = new LambdaQueryWrapper<>();
        directoryNameIsExistAtParentDirectoryWrapper.eq(DirectoryDO::getDirectoryCode, parentCode);
        DirectoryDO directoryDO = directoryMapper.selectOne(directoryNameIsExistAtParentDirectoryWrapper);
        parentDirectoryNameList.add(directoryDO.getDirectoryName());
        // 判断如果上级的父目录编号 = 菜单编号，则表示已经到达顶级目录，结束递归
        if (!directoryDO.getParentCode().equals(directoryDO.getMenuCode().toString())) {
            pathParentDirectoryNameIsRepeat(directoryDO.getParentCode(),parentDirectoryNameList);
        }
        return parentDirectoryNameList;
    }

    /**
     * @author 卑微小峰
     * @param parentCode 父级目录编号
     * @param childDirectoryNameList 子级目录名称集合
     * @return List
     * @description 递归查询同路径上的子级目录
     */
    public List<String> pathChildDirectoryNameIsRepeat(String parentCode,List<String> childDirectoryNameList) {
        // 查询当前父级编号下的所有子目录
        LambdaQueryWrapper<DirectoryDO> getChildDirectoryListWrapper = new LambdaQueryWrapper<>();
        getChildDirectoryListWrapper.eq(DirectoryDO::getParentCode, parentCode);
        List<DirectoryDO> childDirectoryList = directoryMapper.selectList(getChildDirectoryListWrapper);

        // 如果集合长度大于0，表示存在下级目录，遍历集合查询下级目录,否则直接返回数据
        if (childDirectoryList.size() > 0) {
            for (DirectoryDO childDirectory : childDirectoryList) {
                childDirectoryNameList.add(childDirectory.getDirectoryName());
                //再通过其id作为pid查询他的下级目录
                pathChildDirectoryNameIsRepeat(childDirectory.getDirectoryCode(),childDirectoryNameList);
            }
        }
        return childDirectoryNameList;
    }

    /**
     * @author 卑微小峰
     * @param parentCode 父级目录编号
     * @param directoryCodeList 子级目录编号集合
     * @return List
     * @description 获取当前目录及所有子目录的编号
     */
    @Override
    public List<String> getAllDirectoryCode(String parentCode,List<String> directoryCodeList) {
        // 查询当前父级编号下的所有子目录
        LambdaQueryWrapper<DirectoryDO> getChildDirectoryListWrapper = new LambdaQueryWrapper<>();
        getChildDirectoryListWrapper.eq(DirectoryDO::getParentCode, parentCode);
        List<DirectoryDO> childDirectoryList = directoryMapper.selectList(getChildDirectoryListWrapper);

        // 如果集合长度大于0，表示存在下级目录，遍历集合查询下级目录,否则直接返回数据
        if (childDirectoryList.size() > 0) {
            for (DirectoryDO childDirectory : childDirectoryList) {
                directoryCodeList.add(childDirectory.getDirectoryCode());
                //再通过其id作为pid查询他的下级目录
                getAllDirectoryCode(childDirectory.getDirectoryCode(),directoryCodeList);
            }
        }
        return directoryCodeList;
    }
}
